/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package espe.ccsoft.controllers;

import espe.ccsoft.controllers.utils.JsfUtil;
import espe.ccsoft.controllers.utils.Mensajes;
import espe.ccsoft.controllers.utils.PaginationHelper;
import espe.ccsoft.controllers.utils.Validaciones;
import espe.ccsoft.dao.PeriodoDao;
import espe.ccsoft.dao.RutaDao;
import espe.ccsoft.models.Periodo;
import espe.ccsoft.models.Ruta;
import espe.ccsoft.viewmodels.PlantillaHojaTrabajo;
import espe.ccsoft.viewmodels.ResumenHojaTrabajo;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Time;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;

/**
 *
 * @author Carlos
 */
@ManagedBean
@SessionScoped
public class PeriodoController {

    private static List<Periodo> periodos = new ArrayList<>();
    private static List<PlantillaHojaTrabajo> plantilla = new ArrayList<>();
    private static List<ResumenHojaTrabajo> resumen = new ArrayList<>();
    private List<Ruta> rutas=new ArrayList<>();
    private List<PlantillaHojaTrabajo> periodosOrdinarios;
    private List<PlantillaHojaTrabajo> periodosSabados;
    private List<PlantillaHojaTrabajo> periodosDomingos;
    private Map<String, String> tipoDias;
    private Map<String, Integer> tipoRutas;
    private static Periodo periodo;
    private PaginationHelper pagination;
    private PeriodoDao periodoDao;
    private int selectedItemIndex;
    private DataModel items = null;
    private String periodosRepetidos;
    private boolean periodosNuevos;
    private boolean periodoRepetidoLista;
    private final AtomicInteger id_unico = new AtomicInteger();
    private Ruta ruta = new Ruta();
    private final RutaDao rutaDao = new RutaDao();
    Mensajes mensaje;
    Validaciones validaciones;

    String realPath = "";

    public PeriodoController() {
        mensaje = new Mensajes();
        validaciones = new Validaciones();
    }

    
    public void cargarHoras(AjaxBehaviorEvent abe) {
        try {
            ruta = rutaDao.findByNombreDia(periodo.getRutaNombre(), periodo.getTipoDia());
            this.getSelected().setHora((ruta.getInicioHora()));
            periodo.setHora(ruta.getInicioHora());
            periodo.setNumBus(ruta.getNumBuses());
        } catch (Exception ex) {
            Logger.getLogger(PeriodoController.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    public void cargarTipoRuta() throws Exception {
        tipoDias = new HashMap<>();
        for (Ruta r : rutaDao.findByNombres(periodo.getRutaNombre())) {
            tipoDias.put(r.getTipoDia(), r.getTipoDia());
        }
    }

    public void cargarRutas() throws Exception {
        tipoRutas = new HashMap<>();    
        for (Ruta r : rutaDao.findByNombres(ruta.getNombre())) {
            tipoRutas.put(r.getTipoDia(), r.getId());
        }
    }

    public List<PlantillaHojaTrabajo> getPlantilla() {
        return plantilla;
    }

    public Periodo getSelected() {
        if (periodo == null) {
            periodo = new Periodo();
            selectedItemIndex = -1;
        }
        return periodo;
    }

    public String agregarPeriodo() {
        periodo.setRutaId(ruta.getId());
        
        if(validarIngresoLista(periodo)){
        periodo.setId(id_unico.incrementAndGet());
        this.getPeriodos().add(periodo);
        periodoRepetidoLista=false;
        
        }
        else
            periodoRepetidoLista=true;
        
        periodo = new Periodo();
        return null;
    }

    public void eliminarPeriodo(int id_periodo) {
        Iterator<Periodo> iterator = periodos.iterator();
        while (iterator.hasNext()) {
            if (iterator.next().getId() == id_periodo) {
                iterator.remove();
            }
        }
    }

    public String previsualizar() {
        plantilla = new ArrayList<>();
        int count = 1;
        int countAux = 0;
        int numPeriodos = 0;
        int unidad = 1;

        int numVueltas = 1;

        Calendar calendar1 = Calendar.getInstance();
        Calendar calendar2 = Calendar.getInstance();

        Time t2 = Time.valueOf("00:00:00");
        long l2 = t2.getTime();

        Date horaInicial = new Date(l2);
        Date horaAux = null;
        
        for (Periodo aux : this.getPeriodos()) {
            numPeriodos = this.getPeriodos().size();

            if (countAux == numPeriodos - 1) {
                horaAux = new Date(ruta.getFinHora().getTime());
            } else {
                horaAux = this.getPeriodos().get(countAux + 1).getHora();
            }

            do {
                if (count == 1) {
                    horaInicial = new Date(aux.getHora().getTime());
                }

                PlantillaHojaTrabajo plantillaTmp = new PlantillaHojaTrabajo();
                plantillaTmp.setNro(count);
                plantillaTmp.setVuelta(numVueltas);

                plantillaTmp.setHoraSalida(horaInicial);

                Date llegada = SumarHoras(horaInicial, aux.getCiclo());
                plantillaTmp.setHoraLlegada(llegada);

                plantillaTmp.setCiclo(aux.getCiclo());
                plantillaTmp.setIntervalo(aux.getIntervalo());

                if (numVueltas == 1) {
                    plantillaTmp.setTiempoAnden(new Date(l2));
                } else {
                    plantillaTmp.setTiempoAnden(restarHoras(horaInicial, plantilla.get(count - this.getRuta().getNumBuses() - 1).getHoraLlegada()));
                }
                plantillaTmp.setUnidad(unidad);
                unidad = unidad + 1;

                plantilla.add(plantillaTmp);

                long nuevaHora = horaInicial.getTime() + aux.getIntervalo().getTime();
                horaInicial = SumarHoras(horaInicial, aux.getIntervalo());

                if (count % this.ruta.getNumBuses() == 0) {
                    numVueltas = numVueltas + 1;
                    unidad = 1;
                }
                count = count + 1;

            } while (horaInicial.after(horaAux) != true);
            countAux = countAux + 1;
        }

        ResumenTrabajo();
        return null;
    }

    public List<PlantillaHojaTrabajo> getPlantillaTrabajo(List<PlantillaHojaTrabajo> plantillaPeriodos,
            int id_ruta) throws Exception {
        plantillaPeriodos = new ArrayList<>();
        List<Periodo> periodosTmp=getPeriodoDao().findAll(id_ruta);
        
        if(periodosTmp!=null){
        
        int count = 1;
        int countAux = 0;
        int numPeriodos = 0;
        int unidad = 1;

        int numVueltas = 1;

        Calendar calendar1 = Calendar.getInstance();
        Calendar calendar2 = Calendar.getInstance();

        Time t2 = Time.valueOf("00:00:00");
        long l2 = t2.getTime();

        Date horaInicial = new Date(l2);
        Date horaAux = null;
     

        for (Periodo aux : periodosTmp) {
            numPeriodos = periodosTmp.size();

            if (countAux == numPeriodos - 1) {
                horaAux = new Date(ruta.getFinHora().getTime());
            } else {
                horaAux = periodosTmp.get(countAux + 1).getHora();
            }

            do {
                if (count == 19) {
                    System.out.println();
                }

                if (count == 1) {
                    horaInicial = new Date(aux.getHora().getTime());
                }

                PlantillaHojaTrabajo plantillaTmp = new PlantillaHojaTrabajo();
                plantillaTmp.setNro(count);
                plantillaTmp.setVuelta(numVueltas);

                plantillaTmp.setHoraSalida(horaInicial);

                Date llegada = SumarHoras(horaInicial, aux.getCiclo());
                plantillaTmp.setHoraLlegada(llegada);

                plantillaTmp.setCiclo(aux.getCiclo());
                plantillaTmp.setIntervalo(aux.getIntervalo());

                if (numVueltas == 1) {
                    plantillaTmp.setTiempoAnden(new Date(l2));
                } else {
                    plantillaTmp.setTiempoAnden(restarHoras(horaInicial, plantillaPeriodos.get(count - this.rutaDao.findByPK(id_ruta).getNumBuses() - 1).getHoraLlegada()));
                }
                plantillaTmp.setUnidad(unidad);
                unidad = unidad + 1;

                plantillaPeriodos.add(plantillaTmp);
                
                horaInicial = SumarHoras(horaInicial, aux.getIntervalo());
                if (count % this.rutaDao.findByPK(id_ruta).getNumBuses() == 0) {
                    numVueltas = numVueltas + 1;
                    unidad = 1;
                }
                count = count + 1;

            } while (horaInicial.after(horaAux) != true);
            countAux = countAux + 1;
        }

        ResumenTrabajo();
        }
        
        return plantillaPeriodos;
    }
    
    private Date SumarHoras(Date fecha1, Date fecha2) {
        Calendar calendar1 = Calendar.getInstance();
        Calendar calendar2 = Calendar.getInstance();

        calendar1.setTime(fecha1);
        calendar2.setTime(fecha2);

        calendar1.add(Calendar.HOUR_OF_DAY, calendar2.get(Calendar.HOUR_OF_DAY));
        calendar1.add(Calendar.MINUTE, calendar2.get(Calendar.MINUTE));
        return calendar1.getTime();
    }

    private Date restarHoras(Date fecha1, Date fecha2) {
        Calendar calendar1 = Calendar.getInstance();
        Calendar calendar2 = Calendar.getInstance();

        calendar1.setTime(fecha1);
        calendar2.setTime(fecha2);

        calendar1.add(Calendar.HOUR_OF_DAY, -calendar2.get(Calendar.HOUR_OF_DAY));
        calendar1.add(Calendar.MINUTE, -calendar2.get(Calendar.MINUTE));
        return calendar1.getTime();
    }

    public void ResumenTrabajo() {
        resumen = new ArrayList<>();

        for (int i = 0; i < ruta.getNumBuses(); i++) {
            int numVueltas = 0;
            for (PlantillaHojaTrabajo hoja : plantilla) {
                if (hoja.getUnidad() == (i + 1)) {
                    numVueltas++;
                }
            }

            ResumenHojaTrabajo rhtrabajo = new ResumenHojaTrabajo();
            rhtrabajo.setUnidad((i + 1));
            rhtrabajo.setKilometro(new BigDecimal(ruta.getDistancia())
                    .multiply(new BigDecimal(numVueltas)));
            rhtrabajo.setVuelta(numVueltas);

            resumen.add(rhtrabajo);
        }
    }

    public Ruta getRuta() {
        return ruta;
    }

    public void setRuta(Ruta ruta) {
        this.ruta = ruta;
    }

    public PeriodoDao getPeriodoDao() {
        if (periodoDao == null) {
            periodoDao = new PeriodoDao();
        }
        return periodoDao;
    }

    public Periodo getPeriodo() {
        return periodo;
    }

    public List<Periodo> getPeriodos() {
        return periodos;
    }

    public List<ResumenHojaTrabajo> getResumen() {
        return resumen;
    }

    public Map<String, String> getTipoDias() {
        return tipoDias;
    }

    public void setTipoDias(Map<String, String> tipoDias) {
        this.tipoDias = tipoDias;
    }

    public List<Ruta> getRutas() throws Exception {
        rutas=rutaDao.findAll();
        return rutas;
    }

    public void setRutas(List<Ruta> rutas) {
        this.rutas = rutas;
    }

    public final String crearPeriodo() throws Exception {

        if (periodos.size() > 0) {
            getPeriodoDao().delete(periodos.get(0));
            for (Periodo p : periodos) {                
                getPeriodoDao().insert(p);
            }
            mensaje.addMessageSuccefull("Registro exitoso!", "Los periodos fueron registrados correctamente.");                        
            return "Index";
        }
        mensaje.addMessageError("Registro fallido!", "Los periodos no fueron registrados");        
        return null;

    }

    public final void validarIngreso() throws IOException {
        StringBuilder mensaje = new StringBuilder();
        DateFormat formato = new SimpleDateFormat("HH:mm:ss");
        periodosRepetidos = null;

        try {
            for (Periodo p : periodos) {
                if (getPeriodoDao().findOneByValues(p.getRutaId(),
                        p.getHora(), p.getIntervalo(), p.getCiclo(),
                        p.getTipo()) != null) {

                    mensaje = mensaje.append("<strong>El período con los siguientes datos:</strong>")
                            .append("<br/>").append("<strong>Ruta:</strong> ").append(p.getRutaNombre())
                            .append("<br/>").append("<strong>Hora:</strong> ").append(formato.format(p.getHora()))
                            .append("<br/>").append("<strong>Intervalo:</strong> ").append(formato.format(p.getIntervalo()))
                            .append("<br/>").append("<strong>Ciclo:</strong> ").append(formato.format(p.getCiclo()))
                            .append("<br/>").append("<strong>Se encuentra registrado</strong>")
                            .append("<br/><br/>");

                }
            }

            periodosRepetidos = mensaje.toString().isEmpty() ? null : mensaje.toString();
            periodosNuevos = mensaje.toString().isEmpty();

        } catch (Exception ex) {
            FacesContext.getCurrentInstance().getExternalContext()
                    .getResourceAsStream("/Error");
        }
    }
    
    public final boolean validarIngresoLista(Periodo p) {
        for (Periodo per : this.getPeriodos()) {
            if (per.getCiclo().compareTo(p.getCiclo())==0
                    && per.getHora().compareTo(p.getHora())==0
                    && per.getIntervalo().compareTo(p.getIntervalo())==0
                    && per.getTipoDia().equals(p.getTipoDia())
                    && per.getRutaId() == p.getRutaId()) {
                return false;
            }
        }
        return true;
    }

    public DataModel getItems() {
        if (items == null) {
            items = getPagination().createPageDataModel();
        }
        return items;
    }

    public PaginationHelper getPagination() {
        if (pagination == null) {
            pagination = new PaginationHelper(10) {

                @Override
                public int getItemsCount() {
                    try {
                        return getPeriodoDao().findAll().size();
                    } catch (Exception ex) {
                        return 0;
                    }
                }

                @Override
                public DataModel createPageDataModel() {
                    try {
                        return new ListDataModel(getPeriodoDao().findAll());
                    } catch (Exception ex) {
                        return new ListDataModel();
                    }
                }
            };
        }
        return pagination;
    }

    public final String cargarCrearPeriodo() {
        ruta = new Ruta();
        periodo = new Periodo();
        periodos = new ArrayList<>();
        selectedItemIndex = -1;
        return "Crear";
    }

    public final String cargarDetallePeriodo(String codigo) throws Exception {

        ruta = rutaDao.findOneByCodigo(codigo);

        for (Ruta r : rutaDao.findAllByCodigo(codigo)) {
            if (r.getTipoDia().equals("ORDINARIO")) {
                periodosOrdinarios = getPlantillaTrabajo(periodosOrdinarios, r.getId());
            }
            if (r.getTipoDia().equals("SÁBADO")) {
                periodosSabados = getPlantillaTrabajo(periodosSabados, r.getId());
            }
            if (r.getTipoDia().equals("DOMINGO")) {
                periodosDomingos = getPlantillaTrabajo(periodosDomingos, r.getId());
            }
        }

        return "Detalle";
    }

    public String getPeriodosRepetidos() {
        return periodosRepetidos;
    }

    public void setPeriodosRepetidos(String periodosRepetidos) {
        this.periodosRepetidos = periodosRepetidos;
    }

    public boolean isPeriodosNuevos() {
        return periodosNuevos;
    }

    public void setPeriodosNuevos(boolean periodosNuevos) {
        this.periodosNuevos = periodosNuevos;
    }

    public Map<String, Integer> getTipoRutas() {
        return tipoRutas;
    }

    public void setTipoRutas(Map<String, Integer> tipoRutas) {
        this.tipoRutas = tipoRutas;
    }

    public List<PlantillaHojaTrabajo> getPeriodosOrdinarias() {
        if(periodosOrdinarios==null)
            periodosOrdinarios=new ArrayList<>();
        
        return periodosOrdinarios;
    }

    public void setPeriodosOrdinarias(List<PlantillaHojaTrabajo> periodosOrdinarias) {
        this.periodosOrdinarios = periodosOrdinarias;
    }

    public List<PlantillaHojaTrabajo> getPeriodosSabados() {
        if(periodosSabados==null)
            periodosSabados=new ArrayList<>();
        return periodosSabados;
    }

    public void setPeriodosSabados(List<PlantillaHojaTrabajo> periodosSabados) {
        this.periodosSabados = periodosSabados;
    }

    public List<PlantillaHojaTrabajo> getPeriodosDomingos() {
        if(periodosDomingos==null)
            periodosDomingos=new ArrayList<>();
        return periodosDomingos;
    }

    public void setPeriodosDomingos(List<PlantillaHojaTrabajo> periodosDomingos) {
        this.periodosDomingos = periodosDomingos;
    }

    public boolean isPeriodoRepetidoLista() {
        return periodoRepetidoLista;
    }

    public void setPeriodoRepetidoLista(boolean periodoRepetidoLista) {
        this.periodoRepetidoLista = periodoRepetidoLista;
    }

}
